package org.agony2d.gpu.core {
	import flash.display3D.Context3D;
	import flash.geom.Matrix;
	import flash.geom.Matrix3D;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import org.agony2d.core.agony_internal;
	import org.agony2d.gpu.FusionAA;
	import org.agony2d.gpu.supportClasses.programs.ProgramProxy;
	import org.agony2d.gpu.supportClasses.textures.FullTexture;
	import org.agony2d.notify.Notifier;
	
	use namespace agony_internal;
	
	[Event(name = "press",   type = "org.agony2d.notify.AEvent")] 
	[Event(name = "release", type = "org.agony2d.notify.AEvent")] 
	[Event(name = "over",    type = "org.agony2d.notify.AEvent")] 
	[Event(name = "leave",   type = "org.agony2d.notify.AEvent")] 
	[Event(name = "move",    type = "org.agony2d.notify.AEvent")] 
	[Event(name = "click",   type = "org.agony2d.notify.AEvent")]
	
	/** [ NodeAA ]
	 *  [◆]
	 *  	1.  X × Y
	 *  	2.  pivotX × pivotY
	 *  	3.  rotation
	 *  	4.  scaleX × scaleY
	 *  	5.  alpha
	 *  	6.  visible
	 *  	7.  interactive
	 *  	8.  world
	 *  [◆◆]
	 *  	1.  transformCoord
	 *  	2.  collide
	 *  	3.  setCollisionMethod
	 *  	4.  kill
	 */
public class NodeAA extends Notifier {
	
	public function NodeAA() {
		super(null)
		m_x = m_y = m_pivotX = m_pivotY = m_rotation = 0.0
		m_scaleX = m_scaleY = m_alpha = m_cachedAlpha = 1.0
	}
	
	public function get x() : Number {
		return m_x
	}
	
	public function set x( v:Number ) : void {
		if (m_x != v) {
			m_x = v
			m_altered = true
		}
	}
	
	public function get y() : Number {
		return m_y
	}
	
	public function set y( v:Number ) : void {
		if (m_y != v) {
			m_y = v
			m_altered = true
		}
	}
	
	public function get pivotX() : Number {
		return m_pivotX
	}
	
	public function set pivotX( v:Number ) : void {
		if (m_pivotX != v) {
			m_pivotX = v
			m_altered = true
		}
	}
	
	public function get pivotY() : Number {
		return m_pivotY
	}
	
	public function set pivotY( v:Number ) : void {
		if (m_pivotY != v) {
			m_pivotY = v
			m_altered = true
		}
	}
	
	public function get rotation():Number {
		return m_rotation
	}
	
	public function set rotation( v:Number ) : void {
		if (m_rotation != v) {
			m_rotation = v
			m_altered = true
		}
	}
	
	public function get scaleX():Number {
		return m_scaleX
	}
	
	public function set scaleX( v:Number ) : void {
		if (m_scaleX != v) {
			m_scaleX = v
			m_altered = true
		}
	}
	
	public function get scaleY():Number {
		return m_scaleY
	}
	
	public function set scaleY( v:Number ) : void {
		if (m_scaleY != v) {
			m_scaleY = v
			m_altered = true
		}
	}
	
	public function get alpha() : Number {
		return m_alpha
	}
	
	public function set alpha( v:Number ) : void {
		m_alpha = v
	}
	
	public function get visible() : Boolean {
		return !m_invisible
	}
	
	public function set visible( b:Boolean ) : void {
		m_invisible = !b
	}
	
	public function get interactive() : Boolean {
		return !m_intouchable
	}
	
	public function set interactive( b:Boolean ) : void {
		m_intouchable = !b
	}
	
	public function get world() : WorldAA {
		return m_world
	}
	
	public function transformCoord( x:Number, y:Number, toLocal:Boolean = true, result:Point = null ) : Point {
		var node:NodeAA
		
		cachedMatrix.copyFrom(m_matrix)
		node = m_parent
		while (node) {
			cachedMatrix.concat(node.m_matrix)
			node = node.m_parent
		}
		if (toLocal) {
			cachedMatrix.invert()
		}
		if (!result) {
			result = new Point
		}
		result.setTo(cachedMatrix.a * x + cachedMatrix.c * y + cachedMatrix.tx, cachedMatrix.d * y + cachedMatrix.b * x + cachedMatrix.ty)
		return result
	}
	
	public function collide( x:Number, y:Number, global:Boolean = true ) : Boolean {
		if (!global) {
			return this.checkCollisionNode(x, y, false)
		}
		cachedPoint = this.transformCoord(x, y, true, cachedPoint)
		return this.checkCollisionNode(cachedPoint.x, cachedPoint.y, false)
	}
	
	/** callback(localX:Number, localY:Number) : Boolean... */
	public function setCollisionMethod( v:Function ) : void {
		m_collisionMethod = v
	}
	
	override public function kill() : void {
		m_parent.removeNode(this)
		super.kill()
	}
	
	
	agony_internal static const RADIAN_MEDIATOR:Number = Math.PI / 180
	
	agony_internal static var cachedMatrix:Matrix
	agony_internal static var cachedRect:Rectangle
	agony_internal static var cachedPoint:Point
	agony_internal static var g_textureList:Object
	agony_internal static var g_currFullTexture:FullTexture
	agony_internal static var g_currProgram:ProgramProxy
	agony_internal static var g_context3d:Context3D
	agony_internal static var g_matrixQueue:MatrixProp
	agony_internal static var g_convergence:VertexConvergence
	agony_internal static var g_fullWidth:int, g_fullHeight:int
	agony_internal static var g_drawCount:int
	agony_internal static var g_orthoMatrix3d:Matrix3D
	
	agony_internal var m_x:Number, m_y:Number, m_pivotX:Number, m_pivotY:Number, m_rotation:Number, m_scaleX:Number, m_scaleY:Number, m_alpha:Number, m_cachedAlpha:Number
	agony_internal var m_matrix:Matrix = new Matrix
	agony_internal var m_parent:NodeAA
	agony_internal var m_fullTexture:FullTexture
	agony_internal var m_world:WorldAA
	agony_internal var m_collisionMethod:Function
	agony_internal var m_invisible:Boolean, m_intouchable:Boolean, m_altered:Boolean
	
	
	
	final agony_internal function updateNodeMatrix() : void {
		var cos:Number, sin:Number
		
		cos = Math.cos(m_rotation * RADIAN_MEDIATOR)
		sin = Math.sin(m_rotation * RADIAN_MEDIATOR)
		m_matrix.setTo(m_scaleX * cos, m_scaleY * sin, -scaleX * sin, m_scaleY * cos, m_x, m_y)
		if (m_pivotX != 0.0 || m_pivotY != 0.0) {
			m_matrix.tx = m_x - m_matrix.a * m_pivotX - m_matrix.c * m_pivotY;
			m_matrix.ty = m_y - m_matrix.b * m_pivotX - m_matrix.d * m_pivotY;
		}
		m_altered = false
	}
	
	/** overwrite... */
	agony_internal function render( vertexChanged:Boolean, tinted:Boolean ) : void {
		
	}
	
	/** overwrite... */
	agony_internal function removeNode( node:NodeAA ) : void {
		
	}
	
	/** overwrite... */
	agony_internal function checkCollisionNode( localX:Number, localY:Number, forInteract:Boolean ) : NodeAA {
		return null
	}
	
}
}